package net.googlecode.exigenlab.task4.correction;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;

/**
 * Class for change the format of string. It normalize strings (delete tabs,
 * spaces and carriage returns). Make first characters of word in upper case.
 * Reverse words, and adding date to string
 * 
 * @author Poddybniak Petr <a href="mailto:PPoddybniak@gmail.com">Poddybniak
 *         Petr</a>
 * @since 5.04.2011
 */

public class StringNormalizer {
	private final static String SENTENCE = "    A TEST\t    SeNTeNce\n  FIX it, PLEase, AnD replace A Chars.";
	private final static Integer CHANGE_DATE = -20;
	private String[] arrayString;
	private String resultString;

	/**
	 * Constructor of class.
	 */
	public StringNormalizer() {
	}

	/**
	 * Create array which contain separate words from sentence in lower case,
	 * without extra spaces, tabs and carriage returns. First character of
	 * sentence - in upper case.
	 * 
	 * @return array which contain separate words from sentence.
	 */
	private String[] correctString() {
		StringTokenizer st = new StringTokenizer(SENTENCE.toLowerCase());
		String[] resultArray = new String[st.countTokens()];
		for (int i = 0; st.hasMoreTokens(); i++) {
			resultArray[i] = st.nextToken();
		}
		resultArray[0] = this.firstCharUpper(resultArray[0]);
		return resultArray;
	}

	/**
	 * Normalize incoming string.
	 * 
	 * @return normalized string.
	 */
	public String correctSentence() {
		arrayString = this.correctString();
		return this.recoveryString(arrayString);
	}

	/**
	 * Transfer first characters in all words of sentence to upper case.
	 * 
	 * @return changed string with first characters of all words in upper case.
	 */
	public String allFirstCharsUpper() {
		arrayString = this.correctString();
		for (int i = 0; i < arrayString.length; i++) {
			arrayString[i] = this.firstCharUpper(arrayString[i]);
		}
		return this.recoveryString(arrayString);
	}

	/**
	 * Transfer first character of simple word to upper case.
	 * 
	 * @param word
	 *            - incoming string in lower case;
	 * @return first character of word in upper case.
	 */
	private String firstCharUpper(String word) {
		word = word.replaceFirst(word.substring(0, 1), word.substring(0, 1)
				.toUpperCase());
		return word;
	}

	/**
	 * Reverse all words in sentence;
	 * 
	 * @return string in which all the words are reversed.
	 */
	public String reverceSentence() {
		arrayString = this.correctString();
		for (int i = 0; i < arrayString.length; i++) {
			arrayString[i] = this.reverseWord(arrayString[i]);
		}
		return this.recoveryString(arrayString);
	}

	/**
	 * Reverse simple word.
	 * 
	 * @param word
	 *            - incoming string, which need to reverse.
	 * @return reversed string.
	 */
	private String reverseWord(String word) {
		StringBuilder sb = new StringBuilder(word);
		return sb.reverse().toString();
	}

	/**
	 * Replace characters "A" and "a" by "!" in whole sentence.
	 * 
	 * @return string in which all characters "A" and "a" replaced by "!".
	 */
	public String replaceAChars() {
		arrayString = this.correctString();
		for (int i = 0; i < arrayString.length; i++) {
			arrayString[i] = this.replaceACharsInWord(arrayString[i]);
		}
		return this.recoveryString(arrayString);
	}

	/**
	 * Replace characters "A" and "a" by "!" in simple word.
	 * 
	 * @param word
	 *            - incoming string.
	 * @return string in which all characters "A" and "a" replaced by "!"
	 */
	private String replaceACharsInWord(String word) {
		word = word.replaceAll("A", "!");
		return word.replaceAll("a", "!");
	}

	/**
	 * Add date to the end of string.
	 * 
	 * @return result string with date.
	 */
	public String addDateToString() {
		arrayString = this.correctString();
		return this.recoveryString(arrayString).concat(getDateMinusDays());
	}

	/**
	 * Calculate date and return it in dd-MM-yyyy HH:mm format
	 * 
	 * @return string which contains today's date plus <code>CHANGE_DATE</code>
	 *         constant, in format dd-MM-yyyy HH:mm
	 */
	private String getDateMinusDays() {
		Calendar cal = new GregorianCalendar();
		cal.add(Calendar.DAY_OF_YEAR, CHANGE_DATE);
		Date dateMinusDays = cal.getTime();
		SimpleDateFormat formatter = new SimpleDateFormat(" dd-MM-yyyy HH:mm");
		return formatter.format(dateMinusDays);
	}

	/**
	 * Create result string which contains normalized and changed sentence.
	 * 
	 * @param sentence
	 *            - array of normalized and changed words.
	 * @return string which contains normalized sentence.
	 */
	private String recoveryString(String[] sentence) {
		resultString = "";
		for (int i = 0; i < sentence.length; i++) {
			resultString = resultString.concat(sentence[i]);
			resultString = resultString.concat(" ");
		}
		resultString = resultString.trim();
		return resultString;
	}
}
